import {
  Component,
  Input,
  Output,
  EventEmitter,
  HostBinding,
  Inject,
  Optional,
  ViewChild,
  ElementRef,
  AfterContentInit,
} from '@angular/core';
import {
  NgModel,
  NG_VALIDATORS,
  NG_ASYNC_VALIDATORS,
  NG_VALUE_ACCESSOR,
} from '@angular/forms';

import { ElementBase } from '../form/element-base';
import { DateAdapter } from './datetime/date-adapter';
import { fui_DATE_FORMATS, fuiDateFormats } from './datetime/date-formats';

import {DatepickerComponent} from './datepicker.component';

@Component({
  selector: 'fui-datepicker-input',
  templateUrl: './datepicker-input.component.html',
  styleUrls: ['./datepicker-input.component.sass'],
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: DatepickerInputComponent,
    multi: true,
  }],
})
export class DatepickerInputComponent<D> extends ElementBase<D> implements AfterContentInit {
  @HostBinding('class.fui-datepicker-input') hostClass = true;
  _datepicker: DatepickerComponent<D>;
  @Input() placeholder: string;
  @Input() errorMsgs: string[] = [];
  @Input() max: D;
  @Input() min: D;
  @Input() showTime = false;
  @Input() format: string;
  @ViewChild('dateInput', { static: true }) dateInput;

  @Input()
  set datepicker(value: DatepickerComponent<D>) {
    if (value) {
      this._datepicker = value;
      this._datepicker._registerInput(this);
    }
  }
  get datepicker() {
    return this._datepicker;
  }

  get parsedPlaceholder() {
    return this.placeholder || '';
  }

  _valueChange = new EventEmitter<D|null>();

  @ViewChild(NgModel, { static: true }) model: NgModel;

  constructor(
    @Optional() @Inject(NG_VALIDATORS) validators: Array<any>,
    @Optional() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<any>,
    @Inject(fui_DATE_FORMATS) private _dateFormats: fuiDateFormats,
    private _dateAdapter: DateAdapter<D>,
    private elementRef: ElementRef,
  ) {
    super(validators, asyncValidators);
  }

  ngAfterContentInit() {
    if (this._datepicker) {
      this._datepicker.selectedChanged.subscribe((selected: D) => {
        this.value = selected;
        this.selectChange();
      });
    }
  }

  selectChange() {
    if (this.value) {
      this.dateInput.nativeElement.value = this._dateAdapter.format(
        this.value,
        this.format,
      );
    } else {
      this.dateInput.nativeElement.value = '';
    }
  }

  // @Override
  writeValue(value: D) {
    super.writeValue(value);
    this._valueChange.emit(value);
    this.selectChange();
  }

  openDatepicker(event: Event) {
    if (this.datepicker && !this.disabled) {
      this.datepicker.open();
      event.stopPropagation();
    }
  }

  getPopupConnectionElementRef() {
    return this.elementRef;
  }

  inputChange(event) {
    const value = event.target.value;
    let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput);
    date = this._getValidDateOrNull(date);
    this.value = date;
    this._valueChange.emit(date);
  }

  touchInput() {
    this.model.control.markAsTouched();
  }

  /**
   * @param obj The object to check.
   * @returns The given object if it is both a date instance and valid, otherwise null.
   */
  private _getValidDateOrNull(obj: any): D | null {
    return (this._dateAdapter.isDateInstance(obj) && this._dateAdapter.isValid(obj)) ? obj : null;
  }
}
